package com.tang.common.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.api.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.*;
import org.springframework.lang.NonNull;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Field;
import java.util.Date;

import java.util.Map;

/**
 * 请求公共方法
 * @author tang
 * @date 2022/3/4 16:19
 */
@SuppressWarnings("DuplicatedCode")
@Slf4j
public class HttpRequestBaseUtil {


    /**
     * 公共表单POST请求方法
     * @param fromData 表单参数
     * @param t 输出数据
     * @param <R> 输出数据类型
     * @param name 请求名称
     * @throws RestClientException http客户端请求错误
     * @return 输出参数实体
     */
    public static <R> R fromDataPost(
            String baseUrl,
            MultiValueMap<String, Object> fromData,
            Class<R> t,
            MultiValueMap<String, String> headerMap,String name) throws RestClientException {
        long start = System.currentTimeMillis();
        //请求工具
        RestTemplate restTemplate = new RestTemplate();
        //请求头
        HttpHeaders headers = new HttpHeaders();
        //设置请求头为表单请求
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //额外的请求头参数
        if (headerMap != null){
            headers.addAll(headerMap);
        }
        HttpEntity<Object> httpEntity = new HttpEntity<>(fromData, headers);
        //发起请求
        //打印日志
        String logSign = logBuildStart("POST 表单", baseUrl, null, fromData, headerMap,name);
        ResponseEntity<R> exchange = restTemplate.exchange(baseUrl, HttpMethod.POST, httpEntity, t);
        //响应日志
        logBuildEnd(exchange,logSign,start);
        //返回结果
        return exchange.getBody();
    }

    /**
     * 公共POST请求方法
     * @param data 请求体参数
     * @param t 输出数据
     * @param <R> 输出数据类型
     * @param headerMap 请求头参数
     * @param name 请求名称
     * @throws RestClientException http客户端请求错误
     * @return 输出参数实体
     */
    public static <R> R post(
            String baseUrl,
            Object data,
            Class<R> t,
            MultiValueMap<String, String> headerMap,String name) throws RestClientException {
        long start = System.currentTimeMillis();
        //请求工具
        RestTemplate restTemplate = new RestTemplate();
        //请求头
        HttpHeaders headers = new HttpHeaders();
        //请求请求头
        if (headerMap != null){
            headers.addAll(headerMap);
        }
        HttpEntity<Object> httpEntity = new HttpEntity<>(data, headers);
        //发起请求
        String logSign = logBuildStart("POST 表单", baseUrl, null, data, headerMap,name);
        ResponseEntity<R> exchange = restTemplate.exchange(baseUrl, HttpMethod.POST, httpEntity, t);
        //响应日志
        logBuildEnd(exchange,logSign,start);
        //返回结果
        return exchange.getBody();
    }

    /**
     * 公共GET请求方法
     * @param urlData url参数
     * @param t 输出数据
     * @param <R> 输出数据类型
     * @param headerMap 请求头参数
     * @param name 请求名称
     * @throws RestClientException http客户端请求错误
     * @return 输出参数实体
     */
    public static <R> R get(
            String baseUrl,
            Map<String, String> urlData,
            Class<R> t,
            MultiValueMap<String, String> headerMap,String name) throws RestClientException {
        long start = System.currentTimeMillis();
        //请求工具
        RestTemplate restTemplate = new RestTemplate();
        //请求头
        HttpHeaders headers = new HttpHeaders();
        //获得请求参数url
        String urlQuery = HttpUtil.toParams(urlData);
        //请求请求头
        if (headerMap != null){
            headers.addAll(headerMap);
        }
        HttpEntity<Object> httpEntity = new HttpEntity<>(null, headers);
        //打印日志
        String logSign = logBuildStart("GET", baseUrl, urlData, null, headerMap,name);
        //发起请求
        ResponseEntity<R> exchange = restTemplate.exchange(urlData == null ? baseUrl : baseUrl + "?" + urlQuery, HttpMethod.GET, httpEntity, t);
        //响应日志
        logBuildEnd(exchange,logSign,start);
        //返回结果
        return exchange.getBody();
    }

    /**
     * 通过反射生成MultiValueMap对象
     * @param data 需要生成的数据
     * @return MultiValueMap类型数据
     * @throws IllegalAccessException 反射发生意外
     */
    public static MultiValueMap<String, Object> formDataBuild(Object data) throws IllegalAccessException {
        MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
        //循环遍历OaInfoAssess实体中的属性与值
        for (Field field : data.getClass().getDeclaredFields()){
            //设置可以获取私人属性
            field.setAccessible(true);
            Class<?> type = field.getType();
            //属性名
            String valueName =field.getName();
            //属性值
            Object value=  field.get(data);
            if (type != String.class){
                //非String格式需要进行JSON化
                multiValueMap.add(valueName,JSON.toJSONString(value));
            }else {
                multiValueMap.add(valueName,value);
            }
        }
        return multiValueMap;
    }



    /**
     * 构建外部请求日志,用于请求发起之前
     * @param method 请求方式
     * @param baseUrl 请求基本url
     * @param name 请求名称
     * @param urlQuery 请求查询ual
     * @param bodyData 请求体数据
     * @param headerMap 请求头数据
     * @return 请求编号
     */
    public static  String logBuildStart(@NonNull String method,
                                        @NonNull String baseUrl,
                                        Map<String, String> urlQuery,
                                        Object bodyData,
                                        MultiValueMap<String, String> headerMap, String name){
        StringBuilder logBuilder = logStart(name);
        String sign = IdUtil.simpleUUID();
        //请求头
        if (headerMap != null && headerMap.size() != 0){
            logHeader(logBuilder,headerMap);
        }
        logBuilder.append("==============   外部请求结束 等待响应  ==============\n");
        //打印
        log.info(logBuilder.toString(),
                sign,
                baseUrl,
                method,
                urlQuery == null  ? "无" : JSON.toJSONString(urlQuery),
                bodyData == null ? "无"  :JSON.toJSONString(bodyData)
        );
        return sign ;
    }

    /**
     * 构建外部请求日志,用于请求响应
     * @param exchange 执行结果
     * @param sign 请求编号
     * @param startTime 请求开始时间
     */
    public static  void logBuildEnd(ResponseEntity exchange,String sign,long startTime){
        StringBuilder logBuilder = new StringBuilder();
        logBuilder.append("\n\n================   外部请求响应开始   ================\n");
        logBuilder.append("===> 响应编号 : ").append(sign).append("\n");
        logBuilder.append("===> HTTP状态 : ").append(exchange.getStatusCode()).append("\n");
        logBuilder.append("===> 响应时间 : ").append(DateUtil.formatDateTime(new Date())).append("\n");
        logBuilder.append("===> 总共耗时 : ").append(System.currentTimeMillis() - startTime).append("毫秒").append("\n");
        logBuilder.append("===> 响应数据 : ").append(JSON.toJSONString(exchange.getBody())).append("\n");
        logBuilder.append("================   外部请求响应结束   ================\n");
        //打印
        log.info(logBuilder.toString());
    }

    /**
     * 构建请求日志的基本部分
     * @param name 请求接口名称
     * @return 构建好的logBuilder
     */
    public static  StringBuilder logStart(String name){
        StringBuilder logBuilder = new StringBuilder();
        logBuilder.append("\n\n================   外部请求开始   ================\n");
        logBuilder.append("===> 请求名称 : ").append(StringUtils.isBlank(name) ? "未设置" : name).append("\n");
        logBuilder.append("===> 请求编号 : {}\n");
        logBuilder.append("===> 请求URL : {}\n");
        logBuilder.append("===> 请求方式 : {}\n");
        logBuilder.append("===> 请求时间 : ").append(DateUtil.formatDateTime(new Date())).append("\n");
        logBuilder.append("===> 请求参数 : {}\n");
        logBuilder.append("===> 请求体参数 : {}\n");
        return logBuilder;
    }

    /**
     * 填充请求头参数
     * @param logBuilder 构建好的logBuilder
     * @param headerMap 请求头参数
     */
    public static  void logHeader(StringBuilder logBuilder,MultiValueMap<String, String> headerMap){
        for (String key : headerMap.keySet()) {
            logBuilder.append("===Headers=== :").append(key).append(" : ").append(headerMap.get(key)).append("\n");
        }

    }

    public static void main(String[] args) {
        String s = HttpRequestBaseUtil.get("http://www.baidu.com", null, String.class, null,"测试");
    }


}
